package com.xiashitech.agent.instrumentation.spring.controller.apicapture.inst.v_3_1;

import com.xiashitech.agent.config.StartConfig;
import com.xiashitech.agent.constants.ApiParamDataType;
import com.xiashitech.agent.dto.UserRequest;
import com.xiashitech.agent.instrumentation.spring.controller.apicapture.inst.utils.GenerateParamsUtil;
import com.xiashitech.interfaces.agent.dto.api.*;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.*;

public class ApiGenerate_V_3_1 {
    public static Api generateApi(UserRequest userRequest) {
        List<HttpMethod> httpMethod = new ArrayList();
        List<Path> paths = new ArrayList();
        List<String> classPaths = new ArrayList();
        List<String> methodPaths = new ArrayList();
        List<Consumes> consumes = new ArrayList();
        List<Produces> produces = new ArrayList();
        List<Params> requestParams = new ArrayList();
        List<Params> responseParams = new ArrayList();
        Object servletInvocableHandlerMethod = userRequest.getAdviceObject();
        Object servletWebRequest = userRequest.getRequest();
        try {
            //consumes与produces可以为多值，这里不取全量定义的，只获取当前http请求的request和response的值
            Object response = servletWebRequest.getClass().getMethod("getResponse").invoke(servletWebRequest);
            String contentType = (String)response.getClass().getMethod("getContentType").invoke(response);
            consumes.add(Consumes.builder().name(contentType == null ? "application/x-www-form-urlencoded" : contentType).build());
            if(contentType != null) {
                produces.add(Produces.builder().name(contentType).build());
            }

            //httpMethod可以为多值，这里不取全量定义的，只获取当前http请求的request的值
            Object request = servletWebRequest.getClass().getMethod("getRequest").invoke(servletWebRequest);
            httpMethod.add(HttpMethod.builder().name((String)request.getClass().getMethod("getMethod").invoke(request)).build());

            /*
             * 处理controller类上RequestMapping注解，设置请求path
             */
            Class beanType = (Class)servletInvocableHandlerMethod.getClass().getMethod("getBeanType").invoke(servletInvocableHandlerMethod);
            // long reqId = System.nanoTime();
            // System.out.println(reqId + " ApiGenerate_V_3_1 generateApi servletInvocableHandlerMethod: " + servletInvocableHandlerMethod.getClass().getName());
            // System.out.println(reqId + " ApiGenerate_V_3_1 generateApi request: " + request.getClass().getName());
            // System.out.println(reqId + " ApiGenerate_V_3_1 generateApi requestPath: " + request.getClass().getMethod("getRequestURI").invoke(request) + ", " + request.getClass().getMethod("getServletPath").invoke(request) + ", " + request.getClass().getMethod("getContextPath").invoke(request));
            // System.out.println(reqId + " ApiGenerate_V_3_1 generateApi beanType A: " + beanType.getName() + ", " + System.identityHashCode(beanType));


            Optional<Annotation> controllerAnnotation = Optional.empty();
            //-------- Added on 20170717 by chun
            Optional<Class> interfaceOpt = Arrays.stream(beanType.getInterfaces()).findFirst();
            if (interfaceOpt.isPresent()){
                Class interfaceClass = interfaceOpt.get();
                controllerAnnotation = Arrays.stream(interfaceClass.getAnnotations()).filter(annotation -> annotation.annotationType().getName().equals("org.springframework.web.bind.annotation.RequestMapping")).findFirst();
            }
            //----------
            // System.out.println(reqId + " ApiGenerate_V_3_1 generateApi beanType: " + beanType.getName() + ", " + System.identityHashCode(beanType) + ", annotationLength: " + beanType.getAnnotations().length);
            // if(beanType.getAnnotations().length > 0) {
            //     for(Annotation annotation: beanType.getAnnotations())
            //         System.out.println(reqId + " ApiGenerate_V_3_1 generateApi getAnnotation AA: " + annotation.annotationType().getName());
            // }
            if(controllerAnnotation.isPresent()) { // 表示有接口且接口上有注解
                beanType = interfaceOpt.get();
            } else {
                controllerAnnotation = Arrays.stream(beanType.getAnnotations()).filter(annotation -> annotation.annotationType().getName().equals("org.springframework.web.bind.annotation.RequestMapping")).findFirst();
            }

            // System.out.println(reqId + " ApiGenerate_V_3_1 generateApi controllerAnnotation: " + controllerAnnotation.isPresent());
            if(controllerAnnotation.isPresent()) {
                Object requestMapping = controllerAnnotation.get();
                // System.out.println(reqId + " ApiGenerate_V_3_1 generateApi requestMapping: " + requestMapping.getClass().getName());
                String[] values = (String[])requestMapping.getClass().getMethod("value").invoke(requestMapping);
                if(values.length == 0) {
                    // System.out.println(reqId + " ApiGenerate_V_3_1 generateApi: values.length is 0");
                    try {
                        String[] requestMappingPaths = (String[])requestMapping.getClass().getMethod("path").invoke(requestMapping);
                        // System.out.println(reqId + " ApiGenerate_V_3_1 generateApi requestMappingPaths.length: " + requestMappingPaths.length);
                        if(requestMappingPaths.length > 0) {
                            // System.out.println(reqId + " ApiGenerate_V_3_1 generateApi requestMappingPaths exist, size: " + requestMappingPaths.length + ", the first is: " + requestMappingPaths[0]);
                            classPaths.addAll(Arrays.asList(requestMappingPaths));
                        }
                    } catch (Throwable e) {
                        // System.out.println(reqId + " ApiGenerate_V_3_1 generateApi path exception: " + e.getMessage());
                    }
                } else {
                    // System.out.println(reqId + " ApiGenerate_V_3_1 generateApi: values.length exist, size: " + values.length + ", the First is: " + values[0]);
                    classPaths.addAll(Arrays.asList(values));
                }
            }

            /**
             * 处理controller的ResponseBody注解
             */

            Optional<Annotation> responseBodyAnnotation = Arrays.stream(beanType.getAnnotations()).filter(annotation -> annotation.annotationType().getName().equals("org.springframework.web.bind.annotation.ResponseBody") || annotation.annotationType().getName().equals("org.springframework.web.bind.annotation.RestController")).findFirst();
            if(responseBodyAnnotation.isPresent()) {
                if(!produces.stream().anyMatch(producesController -> producesController.getName().contains("json"))) {
                    produces.add(Produces.builder().name("application/json").build());
                }
            }

            /*
             * controller方法注解解析，处理请求path。不处理httpMethod、consumes和produces，因为已经提取当前请求的相关参数作为该次接口请求的内容。
             */
            Method method = (Method)servletInvocableHandlerMethod.getClass().getMethod("getMethod").invoke(servletInvocableHandlerMethod);

            //------- Added on 20170717 by chun
            String methodName = method.getName();
            if (beanType.isInterface() && Objects.nonNull(method)){
                Optional<Method> methodOpt = Arrays.stream(beanType.getMethods()).filter(methodOnInterface ->
                        methodName.equals(methodOnInterface.getName())).findFirst();
                if (methodOpt.isPresent()){
                    method = methodOpt.get();
                }
            }
            //--------

            Arrays.stream(method.getAnnotations()).forEach(annotation -> {
                try {
                    Class<? extends Annotation> annotationType = annotation.annotationType();
                    if(annotationType.getName().equals("org.springframework.web.bind.annotation.RequestMapping") ||
                            annotationType.getName().equals("org.springframework.web.bind.annotation.DeleteMapping") ||
                            annotationType.getName().equals("org.springframework.web.bind.annotation.GetMapping") ||
                            annotationType.getName().equals("org.springframework.web.bind.annotation.PatchMapping") ||
                            annotationType.getName().equals("org.springframework.web.bind.annotation.PostMapping") ||
                            annotationType.getName().equals("org.springframework.web.bind.annotation.PutMapping")) {
                        Object requestMapping = annotation;
                        String[] values = (String[])requestMapping.getClass().getMethod("value").invoke(requestMapping);
                        if(values.length == 0) {
                            try {
                                String[] requestMappingPaths = (String[])requestMapping.getClass().getMethod("path").invoke(requestMapping);
                                if(requestMappingPaths.length > 0) {
                                    methodPaths.addAll(Arrays.asList(requestMappingPaths));
                                }
                            } catch (Throwable e) {
                            }
                        } else {
                            methodPaths.addAll(Arrays.asList(values));
                        }
                    } else if(annotationType.getName().equals("org.springframework.web.bind.annotation.ResponseBody")) {
                        if(!produces.stream().anyMatch(producesForResponseBody -> producesForResponseBody.getName().toLowerCase().contains("json"))) {
                            produces.add(Produces.builder().name("application/json").build());
                        }
                    }
                } catch (Throwable e) {
                    StartConfig.throwableStackPrinter(e);
                }
            });

            /*
             * 处理请求参数
             */
            Object[] methodParameters = (Object[])servletInvocableHandlerMethod.getClass().getMethod("getMethodParameters").invoke(servletInvocableHandlerMethod);
            Arrays.stream(methodParameters).forEach(methodParameter -> {
                try {
                    Class parameterType = (Class)methodParameter.getClass().getMethod("getParameterType").invoke(methodParameter);
                    if(parameterType.getName().equals("javax.servlet.http.HttpServletRequest") ||
                            parameterType.getName().equals("javax.servlet.http.HttpServletResponse") ||
                            parameterType.getName().equals("org.springframework.ui.Model")) {
                        return;
                    }
                    Annotation[] parameterAnnotations = (Annotation[])methodParameter.getClass().getMethod("getParameterAnnotations").invoke(methodParameter);
                    String parameterName = (String)methodParameter.getClass().getMethod("getParameterName").invoke(methodParameter);
                    if(parameterAnnotations.length > 0) {
                        if(Arrays.stream(parameterAnnotations).anyMatch(annotation -> annotation.annotationType().getName().equals("org.springframework.web.bind.annotation.RequestParam")
                                || annotation.annotationType().getName().equals("org.springframework.web.bind.annotation.PathVariable") || annotation.annotationType().getName().equals("org.springframework.web.bind.annotation.CookieValue")
                                || annotation.annotationType().getName().equals("org.springframework.web.bind.annotation.RequestAttribute") || annotation.annotationType().getName().equals("org.springframework.web.bind.annotation.SessionAttribute")
                                || annotation.annotationType().getName().equals("org.springframework.web.bind.annotation.MatrixVariable") || annotation.annotationType().getName().equals("org.springframework.web.bind.annotation.RequestBody")
                                || annotation.annotationType().getName().equals("org.springframework.web.bind.annotation.RequestHeader") || annotation.annotationType().getName().equals("org.springframework.web.bind.annotation.RequestPart"))) {
                            Arrays.stream(parameterAnnotations).forEach(annotation -> {
                                try {
                                    if(annotation.annotationType().getName().equals("org.springframework.web.bind.annotation.RequestParam") || annotation.annotationType().getName().equals("org.springframework.web.bind.annotation.PathVariable")) {
                                        Object requestParam = annotation;
                                        String paramName = "";
                                        String value = (String)requestParam.getClass().getMethod("value").invoke(requestParam);
                                        if(value.isEmpty()) {
                                            try {
                                                String name = (String)requestParam.getClass().getMethod("name").invoke(requestParam);
                                                paramName = name;
                                            } catch (Throwable e) {
                                            }
                                        } else {
                                            paramName = value;
                                        }
                                        if(!"".equals(paramName)) {
                                            requestParams.add(Params.builder().name(paramName).type(ApiParamDataType.fromValue(parameterType.getSimpleName())).build());
                                        } else {
                                            requestParams.add(Params.builder().name(parameterName).type(ApiParamDataType.fromValue(parameterType.getSimpleName())).build());
                                        }
                                    } else if (annotation.annotationType().getName().equals("org.springframework.web.bind.annotation.CookieValue")) {
                                        Object cookieValue = annotation;
                                        String paramName = "";
                                        String value = (String)cookieValue.getClass().getMethod("value").invoke(cookieValue);
                                        if(value.isEmpty()) {
                                            try {
                                                String name = (String)cookieValue.getClass().getMethod("name").invoke(cookieValue);
                                                paramName = name;
                                            } catch (Throwable e) {
                                            }
                                        } else {
                                            paramName = value;
                                        }
                                        if(!"".equals(paramName)) {
                                            requestParams.add(Params.builder().name(paramName).type(ApiParamDataType.fromValue(parameterType.getSimpleName())).specialSource("cookie").build());
                                        } else {
                                            requestParams.add(Params.builder().name(parameterName).type(ApiParamDataType.fromValue(parameterType.getSimpleName())).specialSource("cookie").build());
                                        }
                                    } else if (annotation.annotationType().getName().equals("org.springframework.web.bind.annotation.MatrixVariable")) {
                                        Object matrixVariable = annotation;
                                        String paramName = "";
                                        String value = (String)matrixVariable.getClass().getMethod("value").invoke(matrixVariable);
                                        if(value.isEmpty()) {
                                            try {
                                                String name = (String)matrixVariable.getClass().getMethod("name").invoke(matrixVariable);
                                                paramName = name;
                                            } catch (Throwable e) {
                                            }
                                        } else {
                                            paramName = value;
                                        }
                                        String pathVar = (String)matrixVariable.getClass().getMethod("pathVar").invoke(matrixVariable);
                                        if(!"".equals(paramName)) {
                                            requestParams.add(Params.builder().name(paramName).type(ApiParamDataType.fromValue(parameterType.getSimpleName())).isMatrixVariable(Boolean.TRUE).pathVar(pathVar).build());
                                        } else {
                                            requestParams.add(Params.builder().name(parameterName).type(ApiParamDataType.fromValue(parameterType.getSimpleName())).isMatrixVariable(Boolean.TRUE).pathVar(pathVar).build());
                                        }
                                    } else if (annotation.annotationType().getName().equals("org.springframework.web.bind.annotation.RequestAttribute")) {
                                        Object requestAttribute = annotation;
                                        String paramName = "";
                                        String value = (String)requestAttribute.getClass().getMethod("value").invoke(requestAttribute);
                                        if(value.isEmpty()) {
                                            try {
                                                String name = (String)requestAttribute.getClass().getMethod("name").invoke(requestAttribute);
                                                paramName = name;
                                            } catch (Throwable e) {
                                            }
                                        } else {
                                            paramName = value;
                                        }
                                        if(!"".equals(paramName)) {
                                            requestParams.add(Params.builder().name(paramName).type(ApiParamDataType.fromValue(parameterType.getSimpleName())).specialSource("requestAttribute").build());
                                        } else {
                                            requestParams.add(Params.builder().name(parameterName).type(ApiParamDataType.fromValue(parameterType.getSimpleName())).specialSource("requestAttribute").build());
                                        }
                                    } else if (annotation.annotationType().getName().equals("org.springframework.web.bind.annotation.RequestBody")) {
                                        if(!consumes.stream().anyMatch(consumesForRequestBody -> consumesForRequestBody.getName().toLowerCase().contains("json"))) {
                                            consumes.add(Consumes.builder().name("application/json").build());
                                        }
                                        if(Collection.class.isAssignableFrom(parameterType)) {
                                            Type parameterGenericParameterType = (Type)methodParameter.getClass().getMethod("getGenericParameterType").invoke(methodParameter);
                                            if(parameterGenericParameterType != null && parameterGenericParameterType instanceof ParameterizedType) {
                                                ParameterizedType parameterizedType = (ParameterizedType) parameterGenericParameterType;
                                                for (Type actualType:parameterizedType.getActualTypeArguments()) {
                                                    if(actualType instanceof Class) {
                                                        Class clazzActualType = (Class)actualType;
                                                        if(GenerateParamsUtil.isPrimitiveOrWrap(clazzActualType) || ApiParamDataType.judgeAnalogyPrimitive(clazzActualType.getSimpleName())) {
                                                            requestParams.add(Params.builder().name(parameterName).type(ApiParamDataType.fromValue(parameterType.getSimpleName())).subParams(Arrays.asList(Params.builder().name(parameterName).type(ApiParamDataType.fromValue(clazzActualType.getSimpleName())).build())).build());
                                                        } else {
                                                            requestParams.add(Params.builder().name(parameterName).type(ApiParamDataType.fromValue(parameterType.getSimpleName())).subParams(GenerateParamsUtil.generateParams(clazzActualType)).build());
                                                            GenerateParamsUtil.clearCompletedClass();
                                                        }
                                                    }
                                                }
                                            } else {
                                                requestParams.add(Params.builder().name(parameterName).type(ApiParamDataType.fromValue(parameterType.getSimpleName())).build());
                                            }
                                        } else {
                                            requestParams.addAll(GenerateParamsUtil.generateParams(parameterType));
                                            GenerateParamsUtil.clearCompletedClass();
                                        }
                                    } else if (annotation.annotationType().getName().equals("org.springframework.web.bind.annotation.RequestHeader")) {
                                        Object requestHeader = annotation;
                                        String paramName = "";
                                        String value = (String)requestHeader.getClass().getMethod("value").invoke(requestHeader);
                                        if(value.isEmpty()) {
                                            try {
                                                String name = (String)requestHeader.getClass().getMethod("name").invoke(requestHeader);
                                                paramName = name;
                                            } catch (Throwable e) {
                                            }
                                        } else {
                                            paramName = value;
                                        }
                                        if(!"".equals(paramName)) {
                                            requestParams.add(Params.builder().name(paramName).type(ApiParamDataType.fromValue(parameterType.getSimpleName())).specialSource("requestHeader").build());
                                        } else {
                                            requestParams.add(Params.builder().name(parameterName).type(ApiParamDataType.fromValue(parameterType.getSimpleName())).specialSource("requestHeader").build());
                                        }
                                    } else if (annotation.annotationType().getName().equals("org.springframework.web.bind.annotation.RequestPart")) {
                                        Object requestPart = annotation;
                                        String paramName = "";
                                        String value = (String)requestPart.getClass().getMethod("value").invoke(requestPart);
                                        if(value.isEmpty()) {
                                            try {
                                                String name = (String)requestPart.getClass().getMethod("name").invoke(requestPart);
                                                paramName = name;
                                            } catch (Throwable e) {
                                            }
                                        } else {
                                            paramName = value;
                                        }
                                        if(parameterType.getName().equals("org.springframework.web.multipart.MultipartFile")) {
                                            if(!"".equals(paramName)) {
                                                requestParams.add(Params.builder().name(paramName).type(ApiParamDataType.fromValue(parameterType.getSimpleName())).build());
                                            } else {
                                                requestParams.add(Params.builder().name(parameterName).type(ApiParamDataType.fromValue(parameterType.getSimpleName())).build());
                                            }
                                        } else {
                                            if(!"".equals(paramName)) {
                                                requestParams.add(Params.builder().name(paramName).type(ApiParamDataType.OBJECT.value()).subParams(GenerateParamsUtil.generateParams(parameterType)).build());
                                                GenerateParamsUtil.clearCompletedClass();
                                            } else {
                                                requestParams.add(Params.builder().name(parameterName).type(ApiParamDataType.OBJECT.value()).subParams(GenerateParamsUtil.generateParams(parameterType)).build());
                                                GenerateParamsUtil.clearCompletedClass();
                                            }
                                        }
                                    } else if (annotation.annotationType().getName().equals("org.springframework.web.bind.annotation.SessionAttribute")) {
                                        Object sessionAttribute = annotation;
                                        String paramName = "";
                                        String value = (String)sessionAttribute.getClass().getMethod("value").invoke(sessionAttribute);
                                        if(value.isEmpty()) {
                                            try {
                                                String name = (String)sessionAttribute.getClass().getMethod("name").invoke(sessionAttribute);
                                                paramName = name;
                                            } catch (Throwable e) {
                                            }
                                        } else {
                                            paramName = value;
                                        }
                                        if(!"".equals(paramName)) {
                                            requestParams.add(Params.builder().name(paramName).type(ApiParamDataType.fromValue(parameterType.getSimpleName())).specialSource("sessionAttribute").build());
                                        } else {
                                            requestParams.add(Params.builder().name(parameterName).type(ApiParamDataType.fromValue(parameterType.getSimpleName())).specialSource("sessionAttribute").build());
                                        }
                                    }
                                } catch (Throwable e) {
                                    StartConfig.throwableStackPrinter(e);
                                }
                            });
                        } else {
                            dealMethodRequestParameter(methodParameter,requestParams);
                        }
                    } else {
                        dealMethodRequestParameter(methodParameter,requestParams);
                    }
                } catch (Throwable e) {
                    StartConfig.throwableStackPrinter(e);
                }
            });

            //如果produces为空则设置默认值；consumes从当前请求中获取，不会为空。
            if(produces.size() == 0) {
                produces.add(Produces.builder().name("application/x-www-form-urlencoded").build());
            }

            /*
             * 处理返回值
             */
            Object methodParameterReturnType = servletInvocableHandlerMethod.getClass().getMethod("getReturnType").invoke(servletInvocableHandlerMethod);
            Class methodParameter = (Class)methodParameterReturnType.getClass().getMethod("getParameterType").invoke(methodParameterReturnType);
            if(GenerateParamsUtil.isPrimitiveOrWrap(methodParameter) || ApiParamDataType.judgeAnalogyPrimitive(methodParameter.getSimpleName())) {
                if(!methodParameter.getName().equals("void")) {
                    responseParams.add(Params.builder().name(methodParameter.getSimpleName().toLowerCase()).type(ApiParamDataType.fromValue(methodParameter.getSimpleName())).build());
                }
            } else if("com.alibaba.fastjson.JSONObject".endsWith(methodParameter.getName())) {
                responseParams.add(Params.builder().name(methodParameter.getSimpleName().toLowerCase()).type(ApiParamDataType.JSON_OBJECT.value()).build());
            } else if("com.alibaba.fastjson.JSONArray".endsWith(methodParameter.getName())) {
                responseParams.add(Params.builder().name(methodParameter.getSimpleName().toLowerCase()).type(ApiParamDataType.JSON_ARRAY.value()).build());
            } else if (Collection.class.isAssignableFrom(methodParameter)) {
                Type genericType = (Type)methodParameterReturnType.getClass().getMethod("getGenericParameterType").invoke(methodParameterReturnType);
                if(genericType instanceof ParameterizedType) {
                    ParameterizedType parameterizedType = (ParameterizedType) genericType;
                    for (Type actualType:parameterizedType.getActualTypeArguments()) {
                        if(actualType instanceof Class) {
                            Class clazzActualType = (Class)actualType;
                            if(GenerateParamsUtil.isPrimitiveOrWrap(clazzActualType) || ApiParamDataType.judgeAnalogyPrimitive(clazzActualType.getSimpleName())) {
                                responseParams.add(Params.builder().name(methodParameter.getSimpleName().toLowerCase()).type(ApiParamDataType.fromValue(methodParameter.getSimpleName())).subParams(Arrays.asList(Params.builder().name(methodParameter.getSimpleName().toLowerCase()).type(ApiParamDataType.fromValue(clazzActualType.getSimpleName())).build())).build());
                            } else {
                                responseParams.add(Params.builder().name(methodParameter.getSimpleName().toLowerCase()).type(ApiParamDataType.fromValue(methodParameter.getSimpleName())).subParams(GenerateParamsUtil.generateParams(clazzActualType)).build());
                                GenerateParamsUtil.clearCompletedClass();
                            }
                        }
                    }
                } else {
                    responseParams.add(Params.builder().name(methodParameter.getSimpleName().toLowerCase()).type(ApiParamDataType.fromValue(methodParameter.getSimpleName())).build());
                }
            } else if(methodParameter.isArray()) {
                Class clazzActualType = methodParameter.getComponentType();
                if(GenerateParamsUtil.isPrimitiveOrWrap(clazzActualType) || ApiParamDataType.judgeAnalogyPrimitive(clazzActualType.getSimpleName())) {
                    responseParams.add(Params.builder().name(methodParameter.getSimpleName().toLowerCase()).type(ApiParamDataType.ARRAY.value()).subParams(Arrays.asList(Params.builder().name(methodParameter.getSimpleName().toLowerCase()).type(ApiParamDataType.fromValue(clazzActualType.getSimpleName())).build())).build());
                } else {
                    responseParams.add(Params.builder().name(methodParameter.getSimpleName().toLowerCase()).type(ApiParamDataType.ARRAY.value()).subParams(GenerateParamsUtil.generateParams(clazzActualType)).build());
                    GenerateParamsUtil.clearCompletedClass();
                }
            } else if (Map.class.isAssignableFrom(methodParameter)) {
                responseParams.add(Params.builder().name(methodParameter.getSimpleName().toLowerCase()).type(ApiParamDataType.MAP.value()).build());
            } else if(methodParameter == Object.class) {
                responseParams.add(Params.builder().name(methodParameter.getSimpleName().toLowerCase()).type(ApiParamDataType.OBJECT.value()).build());
            } else {
                responseParams.addAll(GenerateParamsUtil.generateParams(methodParameter));
                GenerateParamsUtil.clearCompletedClass();
            }

            /*
             * 处理path
             */
            // System.out.println(reqId + " ApiGenerate_V_3_1 generateApi: start concat path, classPath size: " + classPaths.size());
            if(classPaths.size() > 0) {
                classPaths.forEach(classPath -> {
                    if(methodPaths.size() > 0) {
                        methodPaths.forEach(methodPath -> {
                            // System.out.println(reqId + " ApiGenerate_V_3_1 generateApi: concat path, classPath: " + classPath + ",methodPath: " + methodPath);
                            paths.add(Path.builder().name(classPath+methodPath).build());
                        });
                    } else {
                        // System.out.println(reqId + " ApiGenerate_V_3_1 generateApi: concat path, classPath: " + classPath + ", no methodPath");
                        paths.add(Path.builder().name(classPath).build());
                    }
                });
            } else {
                if(methodPaths.size() > 0) {
                    methodPaths.forEach(methodPath -> {
                        // System.out.println(reqId + " ApiGenerate_V_3_1 generateApi: concat path, no classPath, only methodPath: " + methodPath);
                        paths.add(Path.builder().name(methodPath).build());
                    });
                }
            }
        } catch (Throwable e) {
            StartConfig.throwableStackPrinter(e);
        }
        return Api.builder().paths(paths).consumes(consumes).produces(produces).httpMethods(httpMethod).requestParams(requestParams).responseParams(responseParams).build();
    }

    private static void dealMethodRequestParameter(Object methodParameter, List<Params> requestParams) {
        try {
            Class parameterType = (Class)methodParameter.getClass().getMethod("getParameterType").invoke(methodParameter);
            String parameterName = (String)methodParameter.getClass().getMethod("getParameterName").invoke(methodParameter);
            if(GenerateParamsUtil.isPrimitiveOrWrap(parameterType) || ApiParamDataType.judgeAnalogyPrimitive(parameterType.getSimpleName())) {
                requestParams.add(Params.builder().name(parameterName).type(ApiParamDataType.fromValue(parameterType.getSimpleName())).build());
            } else if("com.alibaba.fastjson.JSONObject".endsWith(parameterType.getName())) {
                requestParams.add(Params.builder().name(parameterName).type(ApiParamDataType.JSON_OBJECT.value()).build());
            } else if("com.alibaba.fastjson.JSONArray".endsWith(parameterType.getName())) {
                requestParams.add(Params.builder().name(parameterName).type(ApiParamDataType.JSON_ARRAY.value()).build());
            } else if (Collection.class.isAssignableFrom(parameterType)) {
                Type parameterGenericParameterType = (Type)methodParameter.getClass().getMethod("getGenericParameterType").invoke(methodParameter);
                if(parameterGenericParameterType != null && parameterGenericParameterType instanceof ParameterizedType) {
                    ParameterizedType parameterizedType = (ParameterizedType) parameterGenericParameterType;
                    for (Type actualType:parameterizedType.getActualTypeArguments()) {
                        if(actualType instanceof Class) {
                            Class clazzActualType = (Class)actualType;
                            if(GenerateParamsUtil.isPrimitiveOrWrap(clazzActualType) || ApiParamDataType.judgeAnalogyPrimitive(clazzActualType.getSimpleName())) {
                                requestParams.add(Params.builder().name(parameterName).type(ApiParamDataType.fromValue(parameterType.getSimpleName())).subParams(Arrays.asList(Params.builder().name(parameterName).type(ApiParamDataType.fromValue(clazzActualType.getSimpleName())).build())).build());
                            } else {
                                requestParams.add(Params.builder().name(parameterName).type(ApiParamDataType.fromValue(parameterType.getSimpleName())).subParams(GenerateParamsUtil.generateParams(clazzActualType)).build());
                                GenerateParamsUtil.clearCompletedClass();
                            }
                        }
                    }
                } else {
                    requestParams.add(Params.builder().name(parameterName).type(ApiParamDataType.fromValue(parameterType.getSimpleName())).build());
                }
            } else if(parameterType.isArray()) {
                Class clazzActualType = parameterType.getComponentType();
                if(GenerateParamsUtil.isPrimitiveOrWrap(clazzActualType) || ApiParamDataType.judgeAnalogyPrimitive(clazzActualType.getSimpleName())) {
                    requestParams.add(Params.builder().name(parameterName).type(ApiParamDataType.ARRAY.value()).subParams(Arrays.asList(Params.builder().name(parameterName).type(ApiParamDataType.fromValue(clazzActualType.getSimpleName())).build())).build());
                } else {
                    requestParams.add(Params.builder().name(parameterName).type(ApiParamDataType.ARRAY.value()).subParams(GenerateParamsUtil.generateParams(clazzActualType)).build());
                    GenerateParamsUtil.clearCompletedClass();
                }
            } else if (Map.class.isAssignableFrom(parameterType)) {
                requestParams.add(Params.builder().name(parameterName).type(ApiParamDataType.MAP.value()).build());
            } else if(parameterType == Object.class) {
                requestParams.add(Params.builder().name(parameterName).type(ApiParamDataType.OBJECT.value()).build());
            } else {
                requestParams.addAll(GenerateParamsUtil.generateParams(parameterType));
                GenerateParamsUtil.clearCompletedClass();
            }
        } catch (Throwable e) {
            StartConfig.throwableStackPrinter(e);
        }
    }
}
